﻿using LeRenard.Libraries.Templating.Templating.Mapping;
using System.Linq;

namespace LeRenard.Libraries.Templating.Templating
{
    /// <summary>
    /// Implementation of <see cref="IGenericTemplate"/>,
    /// which defines a generic template.
    /// </summary>
    /// <typeparam name="TObject">The type of the object taken into account when generating the values for the placeholders.</typeparam>
    public class GenericTemplate<TObject> : TemplateBase, IGenericTemplate<TObject>
    {
        /// <summary>
        /// Constructs a new <see cref="TemplateBase"/> instance.
        /// </summary>
        /// <param name="templateString"></param>
        /// <exception cref="ArgumentNullException">Thrown when <paramref name="templateString"/> is null or empty.</exception>
        public GenericTemplate(string templateString)
            : base(templateString)
        {
        }

        /// <summary>
        /// Maps a placeholder to a value.
        /// </summary>
        /// <param name="placeholder">The placeholder to be mapped</param>
        /// /// <exception cref="ArgumentNullExcpetion">When <paramref name="placeholder"/> is null or empty.</exception>
        public IGenericTemplateMappingBuilder<TObject> Map(string placeholder)
        {
            ThrowIf.NullOrEmpty(() => placeholder);

            var mappingBuilder = new GenericTemplateMappingBuilder<TObject>(this, placeholder);
            return mappingBuilder;
        }

        /// <summary>
        /// Gets the template with all it's placeholders replaced by the mapped values.
        /// </summary>
        /// <param name="object">The object taken into account when generating the values for the placeholders.</param>
        /// <returns>The with all it's placeholders replaced by the mapped values.</returns>
        public string GetProcessedTemplate(TObject @object)
        {
            var processedTemplateString = this.TemplateString;

            var nonGenericInvokers = this.TemplateMappings
                .Where(m => m is INonGenericTemplateMapping)
                .Cast<INonGenericTemplateMapping>();
            foreach (var mapping in nonGenericInvokers)
                processedTemplateString = processedTemplateString.Replace(mapping.Placeholder, mapping.GetValue());

            var genericInvokers = this.TemplateMappings
                .Where(m => m is IGenericTemplateMapping<TObject>)
                .Cast<IGenericTemplateMapping<TObject>>();
            foreach (var mapping in genericInvokers)
                processedTemplateString = processedTemplateString.Replace(mapping.Placeholder, mapping.GetValue(@object));

            return processedTemplateString;
        }
    }
}
